﻿using System;
using System.Collections;
using System.Text;

namespace softmet.Utils
{
    public class Automaton
    {
        private readonly char[] stringToParse;

        private struct State
        {
            public readonly string Name;
            public readonly Hashtable Transition;

            public State(string name, Hashtable transTable)
            {
                Name = name;
                Transition = transTable;
            }

        } ;

        #region Definition of States
        private readonly State wantHyphen = new State
            ("wantHyphen",
             new Hashtable
                 {
                     {'-', 1},
                     {' ', 0}
                 }
            );

        private readonly State wantKeyLetter = new State
            ("wantKeyLetter",
             new Hashtable
                 {
                     {'r', 2},
                     {'d', 2},
                     {'l', 2},
                     {'m', 2},
                     {'p', 2},
                     {'h', 0},
                     {'e', 2},
                     {'f', 2}
                 }
            );

        private readonly State wantSpace = new State
            ("wantSpace",
             new Hashtable
                 {
                     {' ', 3}
                 }
            );

        private readonly State want1StArgLetter = new State
            ("want1StArgLetter",
             new Hashtable
                 {
                     {'*', 4}
                 }
            );

        private readonly State collectArgsLetters = new State
            ("collectArgsLetters",
             new Hashtable
                 {
                     {' ', 0},
                     {'*', 4}
                 }
            );
        #endregion

        public Automaton(string[] args)
        {
            // теперь между аргументами всего по одному пробелу!!! В конце обязательно добавляем пробел
            stringToParse = (String.Join(" ", args) + " ").ToCharArray();
        }

        public Hashtable Run()
        {
            // Правила перехода заполнены соответственно порядку состояний в массиве states. 
            var states = new[] { wantHyphen, wantKeyLetter, wantSpace, want1StArgLetter, collectArgsLetters };
            var curState = states[0];
            var argBuilder = new StringBuilder();
            var options = new Hashtable();
            var curKey = ' ';

            foreach (var b in stringToParse)
            {
                int nextStateNum;

                if (curState.Name.Equals("wantKeyLetter"))
                    curKey = b;
                if (curState.Name.Equals("collectArgsLetters") || curState.Name.Equals("want1StArgLetter"))
                    if (b == ' ')
                    {
                        options[curKey] = argBuilder.ToString();
                        argBuilder.Remove(0, argBuilder.Length);
                    }
                    else argBuilder.Append(b);

                if (curState.Transition.ContainsKey(b))
                    nextStateNum = (int)curState.Transition[b];
                else if (curState.Transition.ContainsKey('*'))
                    nextStateNum = (int)curState.Transition['*'];
                else
                    throw new Exception("Wrong arguments!"); // прочитали то, по чему нельзя перейти

                curState = states[nextStateNum];
            }
            if (!curState.Name.Equals("wantHyphen")) throw new Exception("Unexpected end of arguments");
            return options;
        }
    }
}
